#include "stlmodelwidget.h"
// #include "ui_stlmodelwidget.h"

STLModelWidget::STLModelWidget(std::shared_ptr<STLReader> stl_reader, QWidget *parent)
{
    m_sp_stl_reader = stl_reader;
    m_p_program = new QOpenGLShaderProgram(this);
    m_p_coord_sys_program = new QOpenGLShaderProgram(this);
    m_sp_model_vertices_convertor = std::make_shared<PointCloudConvertor>();
    m_sp_model_vertices_convertor->convertFrom(m_sp_stl_reader->getModelMeshes());
    QVariant model_data = m_sp_model_vertices_convertor->getModel();
    m_modelVertices = model_data.value<QVector<Vertex>>();
}

STLModelWidget::STLModelWidget(std::shared_ptr<STLReader> stl_reader, const WindowSetting &window_setting)
{
    setFixedSize(window_setting.win_width, window_setting.win_height);
    m_isGrayScaleMode = window_setting.isGrayScaleMode;
    m_isKeyBoardLocked = window_setting.isKeyBoardLocked;
    m_isMouseKeyLocked = window_setting.isMouseKeyLocked;
    m_isMouseWheelLocked = window_setting.isMouseWheelLocked;
    m_isShowAxis = window_setting.isShowAxis;
    m_sp_stl_reader = stl_reader;
    m_p_program = new QOpenGLShaderProgram(this);
    m_p_coord_sys_program = new QOpenGLShaderProgram(this);
    m_sp_model_vertices_convertor = std::make_shared<PointCloudConvertor>();
    m_modelVertices = window_setting.model_vertices;
    m_camera.lookAt(window_setting.cam_eye, window_setting.cam_center, window_setting.cam_up);
}

STLModelWidget::~STLModelWidget()
{
    if(m_p_program)
        delete m_p_program;
    if(m_p_coord_sys_program)
        delete m_p_coord_sys_program;
    if (glIsFramebuffer(m_fbo))
        glDeleteFramebuffers(1, &m_fbo);
    if (glIsTexture(m_fboTexture))
        glDeleteTextures(1, &m_fboTexture);
}

void STLModelWidget::setCurrentCameraPos(QVector3D cameraPos, QVector3D cameraCenter, QVector3D cameraUp)
{
    m_camera.lookAt(cameraPos, cameraCenter, cameraUp);
}

void STLModelWidget::setCurrentCameraPos(FixDirection fixDirection, float angle)
{
    m_camera.surroundOriginThroughFixDirection(fixDirection, angle);
}

QVector3D STLModelWidget::getCurrentCameraPos()
{
    return m_camera.getEye();
}

QVector3D STLModelWidget::getCurrentCameraCenter()
{
    return m_camera.getCenter();
}

QVector3D STLModelWidget::getCurrentCameraUp()
{
    return m_camera.getUp();
}

QVector<Vertex> STLModelWidget::getCurrentModelVertices() const
{
    return m_modelVertices;
}

bool STLModelWidget::getCurrentColorMode() const
{
    return m_isGrayScaleMode;
}

void STLModelWidget::initializeGL()
{
    initializeOpenGLFunctions();
    glEnable(GL_DEPTH_TEST);
    glClearColor(0.3f, 0.5f, 1.0f, 1.0f);
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

    // 初始化摄像机
    m_camera.setPerspective(static_cast<float>(width()) / static_cast<float>(height()), 0.1f, 100.0f);

    // 锁定鼠标
    m_camera.setMouseLockedStatus(false);
    setMouseTracking(true); // 启用鼠标跟踪
    QCursor::setPos(mapToGlobal(QPoint(width() / 5, height() / 5))); // 将鼠标放在左上角避免初始移动时发生模型万向锁

    // 初始化灯光跟随
    updateLightPos(LightMoveMode_em::AsCamera);

    // 编译和链接着色器
    if(!compileAndLinkShaders(m_p_program, ":/vertex_shaders/shaders_code/vs/vertex_shader.vs", ":/fragment_shaders/shaders_code/fs/fragment_shader.fs"))
    {
        qDebug() << "Failed to compile and link shaders.";
        return;
    }
    if(!compileAndLinkShaders(m_p_coord_sys_program, ":/vertex_shaders/shaders_code/vs/coord_sys_vertex_shader.vs", ":/fragment_shaders/shaders_code/fs/coord_sys_fragment_shader.fs"))
    {
        qDebug() << "Failed to compile and link shaders.";
        return;
    }

    // 初始化颜色模式
    m_p_program->bind();
    m_p_program->setUniformValue("grayValueMode", m_isGrayScaleMode);
    m_p_program->release();

    prepareCoordSysData(); // 设置坐标系显示数据

    // 设置模型初始相位，选择不翻转
    calAndSetModelInitPhase(false);

    // 默认使用点云数据
    /* 点云 */
    // m_sp_model_vertices_convertor->convertFrom(m_sp_stl_reader->getModelMeshes());
    // QVariant model_data = m_sp_model_vertices_convertor->getModel();
    // QVector<Vertex> model_vertices = model_data.value<QVector<Vertex>>();
    // m_intersected_points_count = model_vertices.size();
    m_intersected_points_count = m_modelVertices.size();

    /* 点云厚切片 */
    // 模型切片，刀片厚度设为0.1f，表示在投影模长从正到负方向，每0.1f像素距离就为一层
    //m_stlModelLayers = sortPointsByProjectionLengthAlongDirection(m_stlModelPoints, QVector3D(0,1,0), m_bladeThickness);

    // 获取按切片重排序的顶点数组
    //QVector<Vertex> reArrangedPoints = reArrangePointsByLayersTier(m_stlModelLayers);

    if(m_isShowAxis)
    {
        setCoordSysShaderProgramDataFormation(); // 设置坐标系着色器数据指针
        setCoordSysVertexData2Shader();   // 设置坐标系绘制数据
    }

    setModelShaderProgramDataFormation();    // 设置模型相关着色器数据指针
    setModelVertexData2Shader(m_modelVertices); // 设置整体绘制数据
}

void STLModelWidget::resizeGL(int w, int h)
{
    glViewport(0, 0, w, h);
}

void STLModelWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清除颜色和深度缓冲

    // 设置主场景视口
    glViewport(0, 0, this->width(), this->height());

    // 绘制主场景
    m_vao.bind();
    m_p_program->bind();

    m_p_program->setUniformValue("light.position", m_lightPos);
    m_p_program->setUniformValue("light.ambient", m_ambientLight);
    m_p_program->setUniformValue("light.diffuse", m_diffLight);
    m_p_program->setUniformValue("light.specular", m_specLight);

    m_p_program->setUniformValue("material.ambient", m_ambientObj);
    m_p_program->setUniformValue("material.diffuse", m_diffObj);
    m_p_program->setUniformValue("material.specular", m_specObj);
    m_p_program->setUniformValue("material.shininess", m_shininess);

    m_p_program->setUniformValue("model", m_model);
    m_p_program->setUniformValue("view", m_camera.getViewMatrix());
    m_p_program->setUniformValue("projection", m_camera.getProjectionMatrix());

    // 设置法线矩阵
    QMatrix3x3 normModelMatrix = m_model.normalMatrix();
    m_p_program->setUniformValue("normModelMatrix", normModelMatrix);

    // 绘制主场景
    glDrawArrays(GL_TRIANGLES, 0, m_intersected_points_count);

    m_p_program->release();
    m_vao.release();

    // 设置坐标系视口（左下角）
    glViewport(0, 0, this->width() / 10, this->height() / 10);

    // 绘制坐标系
    m_axis_vao.bind();
    m_p_coord_sys_program->bind();

    // 设置正交投影矩阵
    QMatrix4x4 orthoMatrix;
    orthoMatrix.ortho(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);

    // 使用主场景的视图矩阵（清除平移部分）
    QMatrix4x4 viewMatrix = m_camera.getViewMatrix();
    viewMatrix.setColumn(3, QVector4D(0, 0, 0, 1)); // 清除平移部分

    // 设置模型矩阵为单位矩阵
    QMatrix4x4 identityMatrix;
    identityMatrix.setToIdentity();
    m_p_coord_sys_program->setUniformValue("axis_model", identityMatrix);
    m_p_coord_sys_program->setUniformValue("axis_view", viewMatrix); // 使用主场景的视图矩阵
    m_p_coord_sys_program->setUniformValue("axis_projection", orthoMatrix);

    // 绘制坐标系
    glDrawArrays(GL_LINES, 0, m_coordSysPoints.size());

    m_p_coord_sys_program->release();
    m_axis_vao.release();
}

bool STLModelWidget::saveFramebufferToPNG(const QString& filePath, int image_width, int image_height)
{
    makeCurrent();

    //初始化离屏渲染
    initFBO(image_width, image_height);

    // 绑定 FBO 并渲染
    glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);

    glEnable(GL_DEPTH_TEST);
    glClearColor(0.3f, 0.5f, 1.0f, 1.0f);
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glViewport(0, 0, image_width, image_height);

    auto reserved_points = m_modelVertices;
    float reserved_fov = m_camera.getFOV();

    // 设置视窗填充
    setModelViewPortFilled(image_width, image_height, ProjectionType::Orthogonal);

    // 绘制主场景
    m_vao.bind();
    m_p_program->bind();

    m_p_program->setUniformValue("light.position", m_lightPos);
    m_p_program->setUniformValue("light.ambient", m_ambientLight);
    m_p_program->setUniformValue("light.diffuse", m_diffLight);
    m_p_program->setUniformValue("light.specular", m_specLight);

    m_p_program->setUniformValue("material.ambient", m_ambientObj);
    m_p_program->setUniformValue("material.diffuse", m_diffObj);
    m_p_program->setUniformValue("material.specular", m_specObj);
    m_p_program->setUniformValue("material.shininess", m_shininess);

    m_p_program->setUniformValue("model", m_model);
    m_p_program->setUniformValue("view", m_camera.getViewMatrix());
    m_p_program->setUniformValue("projection", m_camera.getProjectionMatrix());

    // 设置法线矩阵
    QMatrix3x3 normModelMatrix = m_model.normalMatrix();
    m_p_program->setUniformValue("normModelMatrix", normModelMatrix);

    // 绘制主场景
    glDrawArrays(GL_TRIANGLES, 0, m_modelVertices.size());

    // 读取像素
    QImage image(image_width, image_height, QImage::Format_RGBA8888);
    glReadPixels(0, 0, image_width, image_height, GL_RGBA, GL_UNSIGNED_BYTE, image.bits());

    // 恢复视图
    m_modelVertices = reserved_points;
    m_camera.setFOV(reserved_fov);
    m_camera.setPerspective(static_cast<float>(width()) / static_cast<float>(height()), 0.1f, 100.0f);

    m_p_program->release();
    m_vao.release();

    // 恢复默认帧缓冲区
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    cleanupFBO();
    doneCurrent();

    // 保存图像
    return image.mirrored(false, true).save(filePath, "PNG");
}

void STLModelWidget::setPureColor(const QVector3D& pure_color)
{
    m_isGrayScaleMode = GL_FALSE;
    m_p_program->bind();
    m_p_program->setUniformValue("grayValueMode", m_isGrayScaleMode);
    m_p_program->release();
    m_sp_model_vertices_convertor->setColor(pure_color, pure_color, pure_color);
    QVariant model_data = m_sp_model_vertices_convertor->getModel();
    m_modelVertices = model_data.value<QVector<Vertex>>();
    setModelVertexData2Shader(m_modelVertices);
    update();
}

void STLModelWidget::updateStackIndexRangeInfo(GLint &count, bool increaseOrDecrease)
{
    if(increaseOrDecrease && m_curShowSlicesIndice + 1 < m_intersected_points_counts.size())
    {
        count += m_intersected_points_counts[m_curShowSlicesIndice];
        m_curShowSlicesIndice++;
    }
    else if(!increaseOrDecrease && m_curShowSlicesIndice > 0)
    {
        count -= m_intersected_points_counts[m_curShowSlicesIndice];
        m_curShowSlicesIndice--;
    }
}

bool STLModelWidget::loadShaderSource(const QString &filePath, QString &source)
{
    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        qDebug() << "Failed to open shader file:" << filePath;
        return false;
    }

    QTextStream stream(&file);
    source = stream.readAll();
    file.close();
    return true;
}

bool STLModelWidget::compileAndLinkShaders(QOpenGLShaderProgram *p_program, const QString& vs_file_path, const QString& fs_file_path)
{
    if(p_program == nullptr)
        return false;

    QString vertexSource, fragmentSource;

    // 加载顶点着色器代码
    if (!loadShaderSource(vs_file_path, vertexSource))
    {
        return false;
    }

    // 加载片段着色器代码
    if (!loadShaderSource(fs_file_path, fragmentSource))
    {
        return false;
    }

    // 编译顶点着色器
    if (!p_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexSource))
    {
        qDebug() << "Vertex shader compile error:" << p_program->log();
        return false;
    }

    // 编译片段着色器
    if (!p_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentSource))
    {
        qDebug() << "Fragment shader compile error:" << p_program->log();
        return false;
    }

    // 链接着色器程序
    if (!p_program->link())
    {
        qDebug() << "Shader program link error:" << p_program->log();
        return false;
    }

    return true;
}

void STLModelWidget::setModelShaderProgramDataFormation()
{
    if(m_p_program == nullptr)
    {
        qDebug()<<"Shader promgram has not been initialized. Abort building shader program.";
        return;
    }
    m_vao.create();
    m_vao.bind();

    m_vbo.create();
    m_vbo.bind();

    m_p_program->bind();
    m_p_program->enableAttributeArray(0);
    m_p_program->setAttributeBuffer(0, GL_FLOAT, offsetof(Vertex, pos), 3, sizeof(Vertex));

    m_p_program->enableAttributeArray(1);
    m_p_program->setAttributeBuffer(1, GL_FLOAT, offsetof(Vertex, norm), 3, sizeof(Vertex));

    m_p_program->enableAttributeArray(2);
    m_p_program->setAttributeBuffer(2, GL_FLOAT, offsetof(Vertex, color), 4, sizeof(Vertex));

    m_vao.release();
    m_vbo.release();
    m_p_program->release();
}

void STLModelWidget::initFBO(int width, int height)
{
    // 创建 FBO 并绑定纹理
    glGenFramebuffers(1, &m_fbo);
    glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);

    // 创建纹理（用于存储渲染结果）
    glGenTextures(1, &m_fboTexture);
    glBindTexture(GL_TEXTURE_2D, m_fboTexture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    glGenRenderbuffers(1, &m_rboDepth);
    glBindRenderbuffer(GL_RENDERBUFFER, m_rboDepth);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_rboDepth);

    // 将纹理附加到帧缓冲
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_fboTexture, 0);

    // 检查 FBO 是否完整
    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
        qWarning("FBO is incomplete!");
    }

    // 恢复默认帧缓冲区
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

void STLModelWidget::cleanupFBO()
{
    if (m_fbo) {
        glDeleteFramebuffers(1, &m_fbo);
        m_fbo = 0;
    }

    if (m_fboTexture) {
        glDeleteTextures(1, &m_fboTexture);
        m_fboTexture = 0;
    }

    if (m_rboDepth) {
        glDeleteRenderbuffers(1, &m_rboDepth);
        m_rboDepth = 0;
    }
}

void STLModelWidget::setCoordSysShaderProgramDataFormation()
{
    if(m_p_coord_sys_program == nullptr)
    {
        qDebug()<<"Shader promgram has not been initialized. Abort building shader program.";
        return;
    }
    m_axis_vao.create();
    m_axis_vao.bind();

    m_axis_vbo.create();
    m_axis_vbo.bind();

    m_p_coord_sys_program->bind();
    m_p_coord_sys_program->enableAttributeArray(0);
    m_p_coord_sys_program->setAttributeBuffer(0, GL_FLOAT, offsetof(Vertex, pos), 3, sizeof(Vertex));

    m_p_coord_sys_program->enableAttributeArray(1);
    m_p_coord_sys_program->setAttributeBuffer(1, GL_FLOAT, offsetof(Vertex, norm), 3, sizeof(Vertex));

    m_p_coord_sys_program->enableAttributeArray(2);
    m_p_coord_sys_program->setAttributeBuffer(2, GL_FLOAT, offsetof(Vertex, color), 4, sizeof(Vertex));

    m_axis_vao.release();
    m_axis_vbo.release();
    m_p_coord_sys_program->release();
}

void STLModelWidget::prepareCoordSysData()
{
    // 清空之前的坐标系数据
    m_coordSysPoints.clear();

    // 定义坐标系的长度
    float axisLength = 1.0f;

    // X轴 (红色)
    m_coordSysPoints.append({QVector3D(0.0f, 0.0f, 0.0f), QVector3D(1.0f, 0.0f, 0.0f), QVector4D(1.0f, 0.0f, 0.0f, 1.0f)}); // 起点
    m_coordSysPoints.append({QVector3D(axisLength, 0.0f, 0.0f), QVector3D(1.0f, 0.0f, 0.0f), QVector4D(1.0f, 0.0f, 0.0f, 1.0f)}); // 终点

    // Y轴 (绿色)
    m_coordSysPoints.append({QVector3D(0.0f, 0.0f, 0.0f), QVector3D(0.0f, 1.0f, 0.0f), QVector4D(0.0f, 1.0f, 0.0f, 1.0f)}); // 起点
    m_coordSysPoints.append({QVector3D(0.0f, axisLength, 0.0f), QVector3D(0.0f, 1.0f, 0.0f), QVector4D(0.0f, 1.0f, 0.0f, 1.0f)}); // 终点

    // Z轴 (蓝色)
    m_coordSysPoints.append({QVector3D(0.0f, 0.0f, 0.0f), QVector3D(0.0f, 0.0f, 1.0f), QVector4D(0.0f, 0.0f, 1.0f, 1.0f)}); // 起点
    m_coordSysPoints.append({QVector3D(0.0f, 0.0f, axisLength), QVector3D(0.0f, 0.0f, 1.0f), QVector4D(0.0f, 0.0f, 1.0f, 1.0f)}); // 终点
}

void STLModelWidget::calAndSetModelInitPhase(bool isFlip = false)
{
    // 计算与设置STL模型初始相位
    m_centroid = m_model_attr_calculator.calModelCentroid(m_sp_stl_reader->getModelMeshes());
    m_model.translate(-m_centroid.x(), -m_centroid.y(), -m_centroid.z());

    // // PCA法计算模型朝向
    // m_initModelPhase = m_model_attr_calculator.calModelInitPhaseNorm(m_sp_stl_reader->getModelMeshes());

    // // 计算旋转轴和旋转角度
    // QVector3D axis = QVector3D::crossProduct(m_initModelPhase, m_camera.getEye()).normalized();
    // float angle = qRadiansToDegrees(acos(QVector3D::dotProduct(m_camera.getEye().normalized(), m_initModelPhase.normalized())));

    // // 构建旋转矩阵
    // QMatrix4x4 rotationMatrix;
    // rotationMatrix.setToIdentity();
    // rotationMatrix.rotate(angle, isFlip ? -axis : axis);

    // // 应用旋转矩阵到模型变换矩阵
    // m_model = rotationMatrix * m_model;
}

void STLModelWidget::updateLightPos(LightMoveMode_em light_mode)
{
    switch(light_mode)
    {
    case LightMoveMode_em::AsCamera:
        m_lightPos = m_camera.getEye();
        break;
    case LightMoveMode_em::Fixed:
        break;
    case LightMoveMode_em::Random:
        break;
    case LightMoveMode_em::Period:
        break;
    }
}

void STLModelWidget::setModelViewPortMatched()
{
    auto M = m_model;
    auto V = m_camera.getViewMatrix();
    const float n = m_camera.getNearPlaneDistance();
    std::vector<float> x_proj(m_modelVertices.size());
    std::vector<float> y_proj(m_modelVertices.size());
    std::transform(std::execution::par,
                   m_modelVertices.begin(), m_modelVertices.end(),
                   x_proj.begin(),
                   [&](const Vertex& v) {
                       auto vec_in_view = V * M * QVector4D(v.pos, 1.0f);
                       float z = -vec_in_view.z();
                       return vec_in_view.x() * n / z;
                   });
    std::transform(std::execution::par,
                   m_modelVertices.begin(), m_modelVertices.end(),
                   y_proj.begin(),
                   [&](const Vertex& v) {
                       auto vec_in_view = V * M * QVector4D(v.pos, 1.0f);
                       float z = -vec_in_view.z();
                       return vec_in_view.y() * n / z;
                   });
    auto [left, right] = std::minmax_element(std::execution::par, x_proj.begin(), x_proj.end());
    auto [bottom, top] = std::minmax_element(std::execution::par, y_proj.begin(), y_proj.end());
    m_camera.setPerspective(*left, *right, *bottom, *top);
    update();
}

void STLModelWidget::setModelViewPortFilled(int win_width, int win_height, ProjectionType projection_type)
{
    if (m_modelVertices.empty())
        return;
    auto M = m_model;
    auto V = m_camera.getViewMatrix();
    double aspect_ratio = static_cast<double>(win_width) / win_height;
    const float n = m_camera.getNearPlaneDistance();
    std::vector<float> x_proj(m_modelVertices.size());
    std::vector<float> y_proj(m_modelVertices.size());
    auto getCoords = (projection_type == ProjectionType::Perspective)
                         ? getProjectionCoords<ProjectionType::Perspective>
                         : getProjectionCoords<ProjectionType::Orthogonal>;
    std::transform(std::execution::par,
                   m_modelVertices.begin(), m_modelVertices.end(),
                   x_proj.begin(),
                   [&](const Vertex& v) {
                       return getCoords(V, M, v, n).first;
                   });
    std::transform(std::execution::par,
                   m_modelVertices.begin(), m_modelVertices.end(),
                   y_proj.begin(),
                   [&](const Vertex& v) {
                       return getCoords(V, M, v, n).second;
                   });
    auto [left_iter, right_iter] = std::minmax_element(std::execution::par, x_proj.begin(), x_proj.end());
    auto [bottom_iter, top_iter] = std::minmax_element(std::execution::par, y_proj.begin(), y_proj.end());
    float left = *left_iter;
    float right = *right_iter;
    float bottom = *bottom_iter;
    float top = *top_iter;
    switch(projection_type)
    {
    case ProjectionType::Perspective:
    {
        float max_x_offset = std::max(std::fabs(left), std::fabs(right));
        float max_y_offset = std::max(std::fabs(bottom), std::fabs(top));
        if (max_x_offset < 1e-6f || max_y_offset < 1e-6f)
            return;
        float filled_fov;
        float required_fov_x = 2.0f * std::atan(max_x_offset / (n * static_cast<float>(aspect_ratio)));
        float required_fov_y = 2.0f * std::atan(max_y_offset / n);
        filled_fov = std::max(required_fov_x, required_fov_y);
        m_camera.setFOV(qRadiansToDegrees(filled_fov));
        m_camera.setPerspective(aspect_ratio, 0.1f, 100.0f);
    }
    break;
    case ProjectionType::Orthogonal:
    {
        // 计算当前模型范围的中心点和半宽高
        float center_x = (left + right) * 0.5f;
        float center_y = (bottom + top) * 0.5f;
        float half_width = (right - left) * 0.5f;
        float half_height = (top - bottom) * 0.5f;

        // 根据窗口宽高比调整范围
        if (half_width / half_height > aspect_ratio) {
            // 以宽度为准，等比缩放高度
            half_height = half_width / aspect_ratio;
        } else {
            // 以高度为准，等比缩放宽度
            half_width = half_height * aspect_ratio;
        }

        // 重新计算边界
        left = center_x - half_width;
        right = center_x + half_width;
        bottom = center_y - half_height;
        top = center_y + half_height;

        m_camera.setOrthogonal(left, right, bottom, top, n, 100.0f);
    }
    break;
    }
    update();
}

void STLModelWidget::applyGrayscaleValues(GrayScaleRange_em gray_scale_range)
{
    m_isGrayScaleMode = GL_TRUE;
    m_p_program->bind();
    m_p_program->setUniformValue("grayValueMode", m_isGrayScaleMode);
    m_p_program->release();

    float gray_value_scale;
    switch(gray_scale_range)
    {
    case GrayScaleRange_em::U8:
        gray_value_scale = 255.0f;
        break;
    case GrayScaleRange_em::U16:
        gray_value_scale = 65535.0f;
        break;
    }

    // TODO(mengjinlang): 这里MSVC的并行库不能用const的数组，只能两段取点了
    QVector3D plane_norm = m_camera.getEye();
    QVector<float> projections;
    projections.reserve(m_modelVertices.size());
    for (const Vertex& v : m_modelVertices)
        projections.append(QVector3D::dotProduct(v.pos, plane_norm));

    auto [minIt, maxIt] = std::minmax_element(projections.begin(), projections.end());
    float minProj = *minIt;
    float maxProj = *maxIt;
    float range = maxProj - minProj;

    std::for_each(std::execution::par,
                  m_modelVertices.begin(),
                  m_modelVertices.end(),
                  [&](Vertex& vertex) {
                      std::size_t i = &vertex - &m_modelVertices[0];
                      float normalized = (projections[i] - minProj) / range;
                      float grayValue = (normalized * gray_value_scale) / gray_value_scale;
                      vertex.color = QVector4D(grayValue, grayValue, grayValue, 1.0f);
                      i++;
                  });
    setModelVertexData2Shader(m_modelVertices);
    update();
}

QVector3D STLModelWidget::transformNormalToModelSpace(const QVector3D &viewNormal)
{
    // 组合模型视图矩阵(去掉平移)
    QMatrix4x4 mv = m_camera.getViewMatrix() * m_model;
    mv.setColumn(3, QVector4D(0, 0, 0, 1));

    // 计算逆转置矩阵
    QMatrix4x4 invTransMv = mv.inverted().transposed();

    // 变换法向量
    return invTransMv.mapVector(viewNormal).normalized();
}

QVector<Layer> STLModelWidget::sortPointsByProjectionLengthAlongDirection(const QVector<Vertex> &model_points, QVector3D norm_direction, float sliceThickness)
{
    // 确保方向向量是单位向量
    norm_direction.normalize();

    // 构建模长哈希表，用下标对应顶点数组
    QList<QPair<qsizetype, float>> modelPointsLength;

    // 计算所有顶点的方向投影向量模长
    for (qsizetype i = 0; i < model_points.size(); ++i)
    {
        float len = QVector3D::dotProduct(model_points[i].pos, norm_direction);
        modelPointsLength.append({i, len});
    }

    // 按照模长降序排序
    std::sort(modelPointsLength.begin(), modelPointsLength.end(), [](const QPair<qsizetype, float>& a, const QPair<qsizetype, float>& b)
              {
                  return a.second > b.second;
              });

    // 从大端到小端，按需求厚度切片
    QVector<Layer> layers;
    if (modelPointsLength.isEmpty())
        return layers;

    // 初始化第一个切片
    Layer currentLayer;
    float currentSliceEnd = modelPointsLength.first().second; // 当前切片的最大模长
    for (qsizetype j = 0; j < modelPointsLength.length(); ++j)
    {
        qsizetype vertexIndex = modelPointsLength[j].first;
        float len = modelPointsLength[j].second;

        // 如果当前点的模长超出当前切片的范围，则创建一个新切片
        if (len < currentSliceEnd - sliceThickness)
        {
            layers.append(currentLayer); // 将当前切片加入结果
            currentLayer = Layer();     // 重置当前切片
            currentSliceEnd = len;      // 更新当前切片的最大模长
        }

        // 将当前点加入当前切片
        currentLayer.points.append(model_points[vertexIndex]);
    }

    // 将最后一个切片加入结果
    if (!currentLayer.points.isEmpty())
        layers.append(currentLayer);

    return layers;
}

QVector<Vertex> STLModelWidget::reArrangePointsByLayersTier(const QVector<Layer> &layers)
{
    QVector<Vertex> verticesRearrangedByLayer;
    for(qsizetype i = 0; i < layers.size(); ++i)
        verticesRearrangedByLayer.append(m_stlModelLayers[i].points);
    return verticesRearrangedByLayer;
}

void STLModelWidget::setModelVertexData2Shader(const QVector<Vertex>& model_vertices)
{
    m_vbo.bind();
    assert(model_vertices.size() * sizeof(Vertex) <= INT_MAX);
    m_vbo.allocate(model_vertices.constData(), model_vertices.size() * sizeof(Vertex)); // 如果顶点数量大于int的最大值，此处会异常
    m_vbo.release();
}

void STLModelWidget::setCoordSysVertexData2Shader()
{
    m_axis_vbo.bind();
    assert(m_coordSysPoints.size() * sizeof(Vertex) <= INT_MAX);
    m_axis_vbo.allocate(m_coordSysPoints.constData(), m_coordSysPoints.size() * sizeof(Vertex)); // 如果顶点数量大于int的最大值，此处会异常
    m_axis_vbo.release();
}

void STLModelWidget::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton && !m_isMouseKeyLocked)
    {
        m_isMousePressed = true; // 标记鼠标按下
        m_lastMousePos = event->pos(); // 记录当前鼠标位置
    }
}

void STLModelWidget::mouseMoveEvent(QMouseEvent *event)
{
    static bool firstMouse = true;

    if (m_isMousePressed)
    {
        // 防抖动
        if (firstMouse)
        {
            m_lastMousePos = event->pos();
            firstMouse = false;
            return;
        }

        // 计算鼠标偏移量
        QPoint delta = event->pos() - m_lastMousePos;
        m_lastMousePos = event->pos();

        m_camera.surroundOriginByMouseInput(delta);

        updateLightPos(LightMoveMode_em::AsCamera);

        // 触发重绘
        update();
    }
}

void STLModelWidget::mouseReleaseEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton && !m_isMouseKeyLocked)
        m_isMousePressed = false; // 标记鼠标释放
}

void STLModelWidget::wheelEvent(QWheelEvent *event)
{
    if(m_isMouseWheelLocked)
        return;

    // 将滚轮事件传递给相机
    m_camera.wheelEvent(event);

    // 更新透视投影矩阵
    m_camera.setPerspective(static_cast<float>(width()) / static_cast<float>(height()), 0.1f, 100.0f);

    //updateStackIndexRangeInfo(m_intersected_points_count, event->angleDelta().y() > 0.0f ? true : false);

    // 触发重绘
    update();
}

void STLModelWidget::keyPressEvent(QKeyEvent *event)
{
    if (event->key() == Qt::Key_Space) {
        saveFramebufferToPNG("untitle.png", this->width(), this->height());
        qDebug() << "Slice saved as slice_output.png";
    }

    // 调用基类的 keyPressEvent 以确保其他键盘事件正常处理
    QOpenGLWidget::keyPressEvent(event);
}
